package com.ego.admin.aspect;

import com.alibaba.fastjson.JSON;
import com.ego.admin.po.SysAdmin;
import com.ego.admin.po.SysOperationLog;
import com.ego.admin.service.SysOperationLogService;
import com.ego.admin.util.IpUtil;
import com.ego.common.annotation.ControllerEndpoint;
import com.ego.common.util.AddressUtil;
import org.apache.shiro.SecurityUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.LocalVariableTableParameterNameDiscoverer;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Objects;

/**
 * @program: ego
 * @description: 系统日志切面
 * @author: KamTang
 * @create: 2023-05-02 09:29
 **/
@Aspect
@Component
public class ControllerEndpointAspect extends AspectSupport {

    private final SysOperationLog log = new SysOperationLog();

    private long startTime = 0;

    @Autowired
    private SysOperationLogService logService;

    /**
     * 切入点
     */
    @Pointcut("@annotation(com.ego.common.annotation.ControllerEndpoint)")
    public void pointcut() {}

    /**
     * 环绕通知
     * @param joinPoint ProceedingJoinPoint
     * @return Object
     */
    @Around("pointcut()")
    public Object saveSysLog (ProceedingJoinPoint joinPoint) throws Throwable {
        Object result;
        startTime = System.currentTimeMillis();

        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();
        // 获取注释（需要一个注释类）
        ControllerEndpoint controllerEndpoint = method.getAnnotation(ControllerEndpoint.class);
        if (controllerEndpoint != null) {
            String operation = controllerEndpoint.operation();
            // 注解上的操作描述
            log.setOperation(operation);
        }

        // 请求参数
        Object[] args = joinPoint.getArgs();
        // LocalVariableTableParameterNameDiscoverer 获取方法的参数名
        LocalVariableTableParameterNameDiscoverer discoverer = new LocalVariableTableParameterNameDiscoverer();
        String[] parameterNames = discoverer.getParameterNames(method);
        log.setParams("paramName:" + Arrays.toString(parameterNames) + ",args:" + Arrays.toString(args));

        // 请求IP
        HttpServletRequest request = ((ServletRequestAttributes) Objects.requireNonNull(RequestContextHolder.getRequestAttributes())).getRequest();
        String ipAddress = IpUtil.getIpAddress(request);
        log.setIp(ipAddress);

        // 操作人
        SysAdmin admin = (SysAdmin) SecurityUtils.getSubject().getPrincipal();
        log.setUsername(admin.getUsername());

        // 执行目标方法
        result = joinPoint.proceed();

        // 请求的方法名
        String className = joinPoint.getTarget().getClass().getName();
        String methodName = signature.getName();
        log.setMethod(className + "." + methodName + "()\n" + "\nresponse:" + postHandle(result));

        // 总耗时
        log.setTime(System.currentTimeMillis() - startTime);

        // 保存系统日志
        logService.saveLog(log);
        return result;
    }


    /**
     * 返回数据
     * @param retVal Object
     * @return JSONString
     */
    private String postHandle(Object retVal) {
        if(null == retVal){
            return "";
        }
        return JSON.toJSONString(retVal);
    }
}
